'use strict'

// <--    还原前    -->
function test() {
    for (var index = 0; index != 5;) {
      switch (index) {
        case 0:
          console.log("This is case-block 0");
          index = 3;
          continue;
  
        case 1:
          console.log("This is case-block 1");
          return;
          index = 5;
          continue;
  
        case 2:
          console.log("This is case-block 2");
          index = 1;
          continue;
  
        case 3:
          console.log("This is case-block 3");
          index = 4;
          continue;
  
        case 4:
          console.log("This is case-block 4");
          index = 2;
          continue;
      }
  
      break;
    }
}

/**
 * <--    特点    -->
 * 1. 类似以数组为基础的循环控制流，将编号放在一个数组中，执行顺序一目了然，
 *    此控制流也是也用循环来获取语句，只不过类似于链表形式，对于下一个要执行的语句是在上个语句中表示
 * 
 * <--    解决办法    -->
 * 1. 从forstmt进入
 * 2. 定义一个指针，指向当前编号
 * 3. 进入无限循环
 * 4. 在SwitchStatement中遍历到给定编号的SwitchCase
 * 5. 将本编号判别值的语句插入到forStatement之前
 *    如果遇到returnStatement，此控制流程终止，跳出循环；如果达到终止编号，跳出循环
 * 6. 预设指针到下一个编号
 * 
 * <--    冗余判断    -->
 * 对ForStatement进行判断，ForStatement.update == null（因为是链表式）
 * 
 **/

// <--    还原后    -->
function test() {
    console.log("This is case-block 0");
    console.log("This is case-block 3");
    console.log("This is case-block 4");
    console.log("This is case-block 2");
    console.log("This is case-block 1");
    return;
}
// <-----------    -->

const {parse}  = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const t = require('@babel/types');
const generator = require('@babel/generator').default;

let xcode = `function test() {
    for (var index = 0; index != 5;) {
      switch (index) {
        case 0:
          console.log("This is case-block 0");
          index = 3;
          continue;
  
        case 1:
          console.log("This is case-block 1");
          return;
          index = 5;
          continue;
  
        case 2:
          console.log("This is case-block 2");
          index = 1;
          continue;
  
        case 3:
          console.log("This is case-block 3");
          index = 4;
          continue;
  
        case 4:
          console.log("This is case-block 4");
          index = 2;
          continue;
      }
  
      break;
    }
  }`;


const visitor = {
    ForStatement:{
        enter:function(forStmt){
            if (!forStmt.get('init').node || !forStmt.get('test').node || forStmt.get('update').node){
                return;
            }
            let cursor = forStmt.get('init.declarations.0');
            let pointLV = cursor.node.id.name, pointRV = cursor.node.init.value;
            let test = forStmt.get('test');
            let switchStmt = forStmt.get('body.body.0');
            let discriminant = switchStmt.get('discriminant');

            while(true){
                // 循环进入条件计算
                let _test = test;
                _test.traverse({
                    Identifier:function(path){
                        if (path.node.name == pointLV){
                            path.replaceInline(t.valueToNode(pointRV));
                        }
                    }
                });
                if (!_test.evaluate().value){
                    break;
                }

                // switch判别式计算
                let _discriminant = discriminant, discriminantVal;
                if (t.isIdentifier(_discriminant.node)){
                    discriminantVal = pointRV;
                }else{
                    _discriminant.traverse({
                        Identifier:function(path){
                            if (path.node.name == pointLV){
                                path.replaceInline(t.valueToNode(pointRV));
                            }
                        }
                    });
                    discriminantVal = _discriminant.evaluate().value;
                }

                console.log(discriminantVal);

                // 找到相应switch case
                let switchCase;
                switchStmt.traverse({
                    SwitchCase:function(path){
                        if(path.get('test').node.value == discriminantVal){
                            switchCase = path;
                        }
                    }
                });

                // 对case中的表达式进行还原
                let isBreak = false;
                for (let innerStmt of switchCase.get('consequent')){
                    if (t.isAssignmentExpression(innerStmt.get('expression').node) && innerStmt.get('expression.left').node.name == pointLV){
                        pointRV = innerStmt.get('expression.right').node.value;
                    } else if (t.isReturnStatement(innerStmt.node)){
                        forStmt.insertBefore(innerStmt.node);
                        isBreak = true;
                        break;
                    } else if (!t.isContinueStatement(innerStmt.node)){
                        forStmt.insertBefore(innerStmt.node);
                    }
                }
                if (isBreak){
                    break;
                }

                // 如果case表达式中无Continue语句，也需要break退出
                isBreak = true;
                switchCase.traverse({
                    ContinueStatement:function(path){
                        isBreak = false
                    }
                });

                if (isBreak){
                    break;
                }
            }

            // scope.bindings 状态更新
            let program = forStmt.parentPath;
            forStmt.remove();
            program.scope.crawl();

        },
    },
}

let ast = parse(xcode);
traverse(ast, visitor);
let {code} = generator(ast, {retainLines:false});
console.log(code);
